home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume7 / rvi / part1 next >
Encoding:
Internet Message Format  |  1986-11-30  |  55.7 KB

  1. Subject:  v07i003:  Vi front-end for remote editing, Part01/04
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: Alan Klietz <ihnp4!dicome!mn-at1!alan>
  6. Mod.sources: Volume 7, Issue 3
  7. Archive-name: rvi/Part01
  8.  
  9.  
  10. #!/bin/sh
  11. # This is a shell archive.  Remove anything before this line,
  12. # then unpack it by saving it in a file and typing "sh file".
  13. # Wrapped by mirror!rs on Wed Aug 27 00:04:44 EDT 1986
  14.  
  15. # Exit status; set to 1 on "wc" errors or if would overwrite.
  16. STATUS=0
  17. # Contents:  BUGFIX BUGFIX2 Makefile.bsd Makefile.usg NEXT_REL README
  18. #    binsearch.c copy.c copyright Manifest regerror.c regexp.c regexp.h
  19. #    regmagic.h rv_change.c rv_column.c rv_delcol.c rv_dot.c
  20.  
  21. echo x - BUGFIX
  22. if test -f BUGFIX ; then
  23.     echo BUGFIX exists, putting output in $$BUGFIX
  24.     OUT=$$BUGFIX
  25.     STATUS=1
  26. else
  27.     OUT=BUGFIX
  28. fi
  29. sed 's/^XX//' > $OUT <<'@//E*O*F BUGFIX//'
  30. XXFix Curses V.2.2 - dereference of null pointer assumes *((char *)0) = '\0'
  31.  
  32. XX*** _dellines.orig    Tue Jan  7 11:58:43 1986
  33. XX--- _dellines.c    Tue Jan  7 11:59:08 1986
  34. XX***************
  35. XX*** 30,36
  36. XX          }
  37. XX          if (SP->ml_above + lines > lines_of_memory)
  38. XX              SP->ml_above = lines_of_memory - lines;
  39. XX!     } else if (parm_delete_line && (n>1 || *delete_line==0)) {
  40. XX          tputs(tparm(parm_delete_line, n, SP->phys_y), lines-SP->phys_y, _outch);
  41. XX      }
  42. XX      else if (change_scroll_region && *delete_line==0) {
  43.  
  44. XX--- 30,36 -----
  45. XX          }
  46. XX          if (SP->ml_above + lines > lines_of_memory)
  47. XX              SP->ml_above = lines_of_memory - lines;
  48. XX!     } else if (parm_delete_line && (n>1 || delete_line==0)) {
  49. XX          tputs(tparm(parm_delete_line, n, SP->phys_y), lines-SP->phys_y, _outch);
  50. XX      }
  51. XX      else if (change_scroll_region && delete_line==0) {
  52. XX***************
  53. XX*** 33,39
  54. XX      } else if (parm_delete_line && (n>1 || *delete_line==0)) {
  55. XX          tputs(tparm(parm_delete_line, n, SP->phys_y), lines-SP->phys_y, _outch);
  56. XX      }
  57. XX!     else if (change_scroll_region && *delete_line==0) {
  58. XX          /* vt100: fake delete_line by changing scrolling region */
  59. XX          /* Save since change_scroll_region homes cursor */
  60. XX          tputs(save_cursor, 1, _outch);
  61.  
  62. XX--- 33,39 -----
  63. XX      } else if (parm_delete_line && (n>1 || delete_line==0)) {
  64. XX          tputs(tparm(parm_delete_line, n, SP->phys_y), lines-SP->phys_y, _outch);
  65. XX      }
  66. XX!     else if (change_scroll_region && delete_line==0) {
  67. XX          /* vt100: fake delete_line by changing scrolling region */
  68. XX          /* Save since change_scroll_region homes cursor */
  69. XX          tputs(save_cursor, 1, _outch);
  70. @//E*O*F BUGFIX//
  71. chmod u=rw,g=rw,o=rw $OUT
  72.  
  73. echo x - BUGFIX2
  74. if test -f BUGFIX2 ; then
  75.     echo BUGFIX2 exists, putting output in $$BUGFIX2
  76.     OUT=$$BUGFIX2
  77.     STATUS=1
  78. else
  79.     OUT=BUGFIX2
  80. fi
  81. sed 's/^XX//' > $OUT <<'@//E*O*F BUGFIX2//'
  82. XXFix disable TIMEOUT feature on read-ahead (for 'notimeout' feature
  83. XXof rvi.)  Not really a bug.
  84.  
  85. XX*** getch.orig    Thu Jan 23 15:09:41 1986
  86. XX--- getch.c    Thu Jan 23 15:11:56 1986
  87. XX***************
  88. XX*** 113,119
  89. XX                      if (SP->kp[i].sends[j] <= 0)
  90. XX                          break;    /* found */
  91. XX                      if (SP->input_queue[j] == -1) {
  92. XX!                         SP->input_queue[j] = _fpk(inf);
  93. XX                          SP->input_queue[j+1] = -1;
  94. XX                      }
  95. XX                      if (SP->kp[i].sends[j] != SP->input_queue[j])
  96.  
  97. XX--- 113,122 -----
  98. XX                      if (SP->kp[i].sends[j] <= 0)
  99. XX                          break;    /* found */
  100. XX                      if (SP->input_queue[j] == -1) {
  101. XX!                         if (win->_use_keypad == 2)
  102. XX!                             read(fileno(inf), &SP->input_queue[j], 1);
  103. XX!                         else
  104. XX!                             SP->input_queue[j] = _fpk(inf);
  105. XX                          SP->input_queue[j+1] = -1;
  106. XX                      }
  107. XX                      if (SP->kp[i].sends[j] != SP->input_queue[j])
  108. @//E*O*F BUGFIX2//
  109. chmod u=rw,g=rw,o=rw $OUT
  110.  
  111. echo x - Makefile.bsd
  112. if test -f Makefile.bsd ; then
  113.     echo Makefile.bsd exists, putting output in $$Makefile.bsd
  114.     OUT=$$Makefile.bsd
  115.     STATUS=1
  116. else
  117.     OUT=Makefile.bsd
  118. fi
  119. sed 's/^XX//' > $OUT <<'@//E*O*F Makefile.bsd//'
  120. XX#
  121. XX# Use this Makefile for building rvi on BSD systems, or
  122. XX# on USG systems using the old termcap-style curses.
  123. XX#
  124. XXCFLAGS= -O
  125. XXLDFLAGS=
  126. XXLIB= -lcurses -ltermlib
  127.  
  128. XXOBJS=   rv_init.o rv_main.o rv_redraw.o rv_input.o rv_move.o rv_cmd.o \
  129. XX    rv_dummy.o rv_print_ln.o rv_scroll.o rv_scroll_bk.o rv_column.o \
  130. XX    rv_where.o rv_misc.o rv_delete.o rv_delcol.o rv_redraw_ln.o \
  131. XX    rv_insert.o rv_undo.o rv_openline.o rv_change.o rv_put.o rv_yank.o \
  132. XX    rv_sync.o rv_xmit.o rv_edit.o rv_fetch.o rv_flash.o rv_dot.o \
  133. XX    rv_join.o rv_forback.o rv_getline.o rv_search.o \
  134. XX    binsearch.o rv_linecmd.o copy.o zero.o  rv_quit.o \
  135. XX    regexp.o regerror.o rv_word.o rv_mark.o rv_shell.o rv_fast.o
  136.  
  137. XXall:  rvtest rvi
  138.  
  139. XXrvtest: rvtest.c
  140. XX    $(CC) rvtest.c -o rvtest
  141.  
  142. XXrvi: $(OBJS)
  143. XX    $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIB) -o rvi
  144.  
  145. XXprint:
  146. XX    pr -f rv.h rv*.c > list
  147. XX    reverse list > list2
  148. XX    qpr -q sw list2
  149. XX    rm -f list list2
  150.  
  151. XXbackup:
  152. XX    cp *.[ch] bak
  153.  
  154. XXlint:
  155. XX    lint *.c $(LIB)
  156.  
  157. XXclean:
  158. XX    rm -f *.o
  159. @//E*O*F Makefile.bsd//
  160. chmod u=rw,g=rw,o=rw $OUT
  161.  
  162. echo x - Makefile.usg
  163. if test -f Makefile.usg ; then
  164.     echo Makefile.usg exists, putting output in $$Makefile.usg
  165.     OUT=$$Makefile.usg
  166.     STATUS=1
  167. else
  168.     OUT=Makefile.usg
  169. fi
  170. sed 's/^XX//' > $OUT <<'@//E*O*F Makefile.usg//'
  171. XX#
  172. XX# Use this Makefile for building rvi on USG systems (with terminfo).
  173. XX#
  174. XXCFLAGS= -O -DKEYPAD -DVIDEO
  175. XXLDFLAGS=
  176. XXLIB= -lcurses
  177.  
  178. XXOBJS=   rv_init.o rv_main.o rv_redraw.o rv_input.o rv_move.o rv_cmd.o \
  179. XX    rv_dummy.o rv_print_ln.o rv_scroll.o rv_scroll_bk.o rv_column.o \
  180. XX    rv_where.o rv_misc.o rv_delete.o rv_delcol.o rv_redraw_ln.o \
  181. XX    rv_insert.o rv_undo.o rv_openline.o rv_change.o rv_put.o rv_yank.o \
  182. XX    rv_sync.o rv_xmit.o rv_edit.o rv_fetch.o rv_flash.o rv_dot.o \
  183. XX    rv_join.o rv_forback.o rv_getline.o rv_search.o \
  184. XX    binsearch.o rv_linecmd.o copy.o zero.o  rv_quit.o \
  185. XX    regexp.o regerror.o rv_word.o rv_mark.o rv_shell.o rv_fast.o
  186.  
  187. XXall:  rvtest rvi
  188.  
  189. XXrvtest: rvtest.c
  190. XX    $(CC) rvtest.c -o rvtest
  191.  
  192. XXrvi: $(OBJS)
  193. XX    $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIB) -o rvi
  194.  
  195. XXprint:
  196. XX    pr -f rv.h rv*.c > list
  197. XX    reverse list > list2
  198. XX    qpr -q sw list2
  199. XX    rm -f list list2
  200.  
  201. XXbackup:
  202. XX    cp *.[ch] bak
  203.  
  204. XXlint:
  205. XX    lint *.c $(LIB)
  206.  
  207. XXclean:
  208. XX    rm -f *.o
  209. @//E*O*F Makefile.usg//
  210. chmod u=rw,g=rw,o=rw $OUT
  211.  
  212. echo x - NEXT_REL
  213. if test -f NEXT_REL ; then
  214.     echo NEXT_REL exists, putting output in $$NEXT_REL
  215.     OUT=$$NEXT_REL
  216.     STATUS=1
  217. else
  218.     OUT=NEXT_REL
  219. fi
  220. sed 's/^XX//' > $OUT <<'@//E*O*F NEXT_REL//'
  221.  
  222. XXI have fixed some bugs in in the version of RVI that is posted to mod.sources
  223. XXin Volume 7.   These bugs were found and repaired during the several
  224. XXweeks it took for rvi to work its way through the network to mod.sources.
  225. XXI would like to thank Richard Salz for his patience and effort in helping
  226. XXme find a reliable path to his machine to get the darn thing posted already.
  227.  
  228. XXThese bugs were pointed out to me by users at the Minnesota Supercomputer
  229. XXCenter.   I am indebted to their persistant efforts, both in finding the
  230. XXbugs, and in their efforts to coax me into fixing them.
  231.  
  232. XXA list of bugs appears below.   I want to wait a few weeks before sending
  233. XXthe diffs so that I may incorporate additional bugfixes received from users
  234. XXimplementing the original distribution.
  235.  
  236. XXIn the meantime, a version of rvi that incorporates the bugfixes received
  237. XXso far is available via anonymous ftp.  The internet address is:
  238. XX    umn-rei-uc.ARPA
  239. XXThe sources containing the bugfixes are stored in /staff/rvi/src.
  240.  
  241. XXA list of bugfixes follows.
  242.  
  243. XX------------------------------------------------------------------
  244.  
  245. XXRvi now can fake deleteln and insertln for dumb terminals that do not
  246. XXhave a change_scroll or insertln/deleteln function.
  247.  
  248. XXw <file> resets the file_modified flag.
  249.  
  250. XXA possible coredump caused by deleting the last line in the file was fixed.
  251.  
  252. XXA spurious ed error message on editing an empty file was removed.
  253.  
  254. XXEditing a nameless file is now handled correctly for a few bad cases.
  255.  
  256. XXRemote invokation of rm and echo was changed to avoid conflicts with
  257. XXshell aliasing.
  258.  
  259. XXSome error messages were made more verbose.
  260.  
  261. XXRvi can now interrogate the terminal type remotely (requires putenv()).
  262.  
  263. XX------------------------------------------------------------------
  264.  
  265.  
  266. XXPlease send your bug reports to   ..ihnp4!dicome!mn-at1!alan.UUCP
  267. XX                 or   aek@umn-rei-uc.ARPA
  268.  
  269. XXThank you.
  270. XX--
  271. XXAlan Klietz
  272. XXMinnesota Supercomputer Center
  273. XX1200 Washington Avenue South
  274. XXMinneapolis, MN  55415
  275. XXPh: +1 612 638 0577        ARPA:  aek@umn-rei-uc.ARPA
  276. XX                UUCP:  ..ihnp4!dicome!mn-at1!alan
  277.  
  278. XX(*) An affiliate of the University of Minnesota
  279.  
  280.  
  281. @//E*O*F NEXT_REL//
  282. chmod u=rw,g=rw,o=rw $OUT
  283.  
  284. echo x - README
  285. if test -f README ; then
  286.     echo README exists, putting output in $$README
  287.     OUT=$$README
  288.     STATUS=1
  289. else
  290.     OUT=README
  291. fi
  292. sed 's/^XX//' > $OUT <<'@//E*O*F README//'
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301. XX  Rvi is a portable distributed screen editor (DSE).  It generates ``ed''
  302. XX  commands for execution on a remote machine.  It was originally developed
  303. XX  for remote screen editing on CRAY-2 supercomputers.
  304.  
  305. XX  Rvi is most useful
  306.  
  307. XX    o To do screen editing machines where a normal screen editor
  308. XX      is inappropriate (e.g. supercomputers, IBM mainframes)
  309.  
  310. XX    o In a distributed computing environment
  311.  
  312. XX    o Across slow networks (e.g. satellites, ARPANET)
  313.  
  314.  
  315. XX  Portability was emphasized over efficiency.  (For example, it 
  316. XX  uses curses rather than doing the CRT manipulations directly)
  317.  
  318.  
  319. XX  Rvi has been tested on a number of machines, including
  320.  
  321. XX    Sun Microsystems SUN 2 and 3
  322. XX    DEC VAX-750/780 (both SV and 4.2)
  323. XX    AT&T UNIX PC
  324. XX    IBM PC AT (Xenix 5 and iAPX268 V)
  325. XX    Silicon Graphics IRIS (V)
  326. XX    Gould CONCEPT 32 (UTX/32)
  327. XX    Apollo (Domain IX)
  328. XX    CRAY-2 (UNICOS) [loopback]
  329.  
  330. XX    
  331.  
  332. XXHow to make rvi:
  333.  
  334. XX    Unpack the shar files.
  335.  
  336. XX    If you have termcap, type  cp Makefile.bsd Makefile
  337.  
  338. XX    If you have terminfo, type cp Makefile.usg Makefile. Also
  339. XX    you should install BUGFIX and BUGFIX2 into your terminfo
  340. XX    library.  (In particular, BUGFIX is required so that vt100
  341. XX    terminals perform insert/delete line properly.)
  342.  
  343. XX    Type ``make''
  344.  
  345. XX    Test rvi by running rvtest.
  346.  
  347.  
  348.  
  349. XXRvi talks through pipe file descriptors to ed.  The pipe descriptors should
  350. XXbe created by your terminal program, e.g. TELNET.  You are responsible for
  351. XXmaking the necessary modifications to your TELNET program to do this.
  352.  
  353. XXYour TELNET program should catch an escape sequence (such as ^]rvi).  It
  354. XXshould then emit a /bin/ed command to the remote machine, create two pipes
  355. XXon the local machine, and exec rvi.
  356.  
  357.  
  358. XXRemember:
  359.  
  360. XXRvi only emits whole lines terminated by a linefeed.  You do not need to
  361. XXchange the terminal modes; rvi takes care of that.   Remember to disable
  362. XXlocal and remote echoing, and do not attempt nl-cr mapping.
  363.  
  364.  
  365.  
  366. XXBugs:
  367.  
  368. XXThe screen is redrawn twice on a full screen update across a window
  369. XXboundary.  This is due to the nature of the window fetching algorithm.
  370.  
  371. XXSome heuristics are used to determine the version of the ed program.
  372. XXRvi may get confused by a non-standard version of ed (e.g. a version
  373. XXof ed that print prompts.)
  374.  
  375. XXTermcap's Curses does not handle the "xn" braindamage flag.  I had to
  376. XXhack in support for it.
  377.  
  378. XXUseful commands such as %, <, and > are not supported because I can't
  379. XXthink of a way to do them efficiently via ed.
  380.  
  381. XXMacros and tags are not supported.
  382.  
  383. XXScrolling is slow under terminfo.
  384.  
  385.  
  386. XX--
  387. XXAlan Klietz
  388. XXMinnesota Supercomputer Center (*)
  389. XX2520 Broadway Drive
  390. XXLauderdale, MN  55113     UUCP:  ..ihnp4!dicome!mn-at1!alan.UUCP
  391. XXPh: +1 612 638 0577              ..caip!meccts!dicome!mn-at1!alan.UUCP
  392. XX                          ARPA:  aek@umn-rei-uc.ARPA
  393.  
  394. XX(*) Formerly titled Research Equipment Incorporated.
  395. XX    An affiliate of the University of Minnesota
  396. @//E*O*F README//
  397. chmod u=rw,g=rw,o=rw $OUT
  398.  
  399. echo x - binsearch.c
  400. if test -f binsearch.c ; then
  401.     echo binsearch.c exists, putting output in $$binsearch.c
  402.     OUT=$$binsearch.c
  403.     STATUS=1
  404. else
  405.     OUT=binsearch.c
  406. fi
  407. sed 's/^XX//' > $OUT <<'@//E*O*F binsearch.c//'
  408. XX/*        binsearch - do a binary search of a structure.
  409. XX        84/04/07.  A. E. Klietz.
  410. XX*/
  411.  
  412. XXbinsearch(match_string, structarray, size_struct, num_structs)
  413. XX/* Search an array of structures for the "match_string" and return
  414. XX            -2 if match_string is not unique
  415. XX            -1 if match_string was not found
  416. XX             i if ith structure matches match_string
  417.  
  418. XX   Each structure contains a string to be compared.
  419. XXThe structure array must be alphabetized.  No error message is
  420. XXprinted.
  421. XX    The structure must be aligned at least as well as a pointer. */
  422.  
  423. XXchar    *match_string;    /* string to match */
  424. XXregister char    *structarray;    /* array of structures to search */
  425. XXshort     size_struct;    /* size of each structure element in bytes */
  426. XXshort     num_structs;    /* number of structures in array */
  427. XX{
  428.  
  429. XXregister short    pos, diff, lower, upper, indx;
  430.  
  431. XX    if (match_string[0] == '\0') /* if null string */
  432. XX        return(-1);  /* no match */
  433.  
  434. XX    lower = 0;
  435. XX    upper = num_structs - 1;
  436. XX    do {
  437. XX        pos = (lower + upper) / 2;
  438. XX        diff = strcmp(&structarray[indx = pos * size_struct], match_string);
  439. XX        if (diff <= 0) /* if match_string >= &structarray[pos] */
  440. XX            lower = pos + 1;
  441. XX        if (diff >= 0) /* if match_string <= &structarray[pos] */
  442. XX            upper = pos - 1;
  443. XX    } while (lower <= upper);
  444.  
  445. XX    if (strcmp(&structarray[indx], match_string) == 0) 
  446. XX        return(pos);
  447.  
  448. XX    if (!substring(match_string, &structarray[indx])) {
  449. XX        ++pos;
  450. XX        indx = pos * size_struct;
  451. XX        if (pos > num_structs - 1 || !substring(match_string, &structarray[indx]))
  452. XX            return(-1);
  453. XX    }
  454. XX    
  455. XX    if (pos < num_structs - 1)
  456. XX        if (substring(match_string, &structarray[(pos + 1) * size_struct]))
  457. XX            return(-2); /* not unique error. */
  458.  
  459. XX    return(pos);
  460. XX}
  461.  
  462.  
  463. XXsubstring(part, full)
  464. XX/* Returns TRUE if "part" is a left anchored substring of "full". */
  465.  
  466. XXregister char    *part, *full;
  467. XX{
  468. XX    register    char    ch;
  469.  
  470. XX    while ((ch = *part++) == *full++ && ch != '\0')
  471. XX        ;
  472. XX    return(ch == '\0');    
  473. XX}
  474. @//E*O*F binsearch.c//
  475. chmod u=rw,g=rw,o=rw $OUT
  476.  
  477. echo x - copy.c
  478. if test -f copy.c ; then
  479.     echo copy.c exists, putting output in $$copy.c
  480.     OUT=$$copy.c
  481.     STATUS=1
  482. else
  483.     OUT=copy.c
  484. fi
  485. sed 's/^XX//' > $OUT <<'@//E*O*F copy.c//'
  486. XX/*    copy - copy data structures
  487. XX    84/12/18.  A. E. Klietz.
  488. XX*/
  489.  
  490. XX#include "rv.h"
  491.  
  492. XX#ifdef copy
  493. XX#undef copy
  494. XX#endif
  495.  
  496. XX#ifndef USG
  497. XXvoid
  498. XXcopy(to, from, len)
  499. XXchar *to, *from;
  500. XXint len;
  501. XX{
  502. XX    for (; len > 0; --len)
  503. XX        *(to++) = *(from++);
  504. XX}
  505. XX#endif
  506. @//E*O*F copy.c//
  507. chmod u=rw,g=rw,o=rw $OUT
  508.  
  509. echo x - copyright
  510. if test -f copyright ; then
  511.     echo copyright exists, putting output in $$copyright
  512.     OUT=$$copyright
  513.     STATUS=1
  514. else
  515.     OUT=copyright
  516. fi
  517. sed 's/^XX//' > $OUT <<'@//E*O*F copyright//'
  518. XX/*
  519. XX *    Rvi - Portable distributed screen editor (DSE).
  520. XX *    86/07/16.  Alan Klietz
  521. XX *    Copyright (c) 1986, Research Equipment Incorporated
  522. XX *                          Minnesota Supercomputer Center
  523. XX *
  524. XX * Permission is hereby granted to use this software on any computer system
  525. XX * and to copy this software, including for purposes of redistribution, subject
  526. XX * to the conditions that 
  527. XX *
  528. XX *  o  The full text of this copyright message is retained and prominently
  529. XX *      displayed
  530. XX *
  531. XX *  o  No misrepresentation is made as to the authorship of this software
  532. XX *
  533. XX *  o  The software is not used for resale or direct commercial advantage
  534. XX *
  535. XX *  By copying, installing, or using this software, the user agrees to abide
  536. XX *  by the above terms and agrees that the software is accepted on an "as is"
  537. XX *  basis, WITHOUT WARRANTY expressed or implied, and relieves Research Equip-
  538. XX *  ment Inc., its affiliates, officers, agents, and employees of any and all
  539. XX *  liability, direct of consequential, resulting from copying, installing
  540. XX *  or using this software.
  541. XX */
  542. @//E*O*F copyright//
  543. chmod u=rw,g=rw,o=rw $OUT
  544.  
  545. echo x - Manifest
  546. if test -f Manifest ; then
  547.     echo Manifest exists, putting output in $$Manifest
  548.     OUT=$$Manifest
  549.     STATUS=1
  550. else
  551.     OUT=Manifest
  552. fi
  553. sed 's/^XX//' > $OUT <<'@//E*O*F Manifest//'
  554. XXBUGFIX
  555. XXBUGFIX2
  556. XXMakefile.bsd
  557. XXMakefile.usg
  558. XXNEXT_REL
  559. XXREADME
  560. XXbinsearch.c
  561. XXcopy.c
  562. XXcopyright
  563. XXManifest
  564. XXregerror.c
  565. XXregexp.c
  566. XXregexp.h
  567. XXregmagic.h
  568. XXrv.h
  569. XXrv_change.c
  570. XXrv_cmd.c
  571. XXrv_column.c
  572. XXrv_delcol.c
  573. XXrv_delete.c
  574. XXrv_dot.c
  575. XXrv_dummy.c
  576. XXrv_edit.c
  577. XXrv_fast.c
  578. XXrv_fetch.c
  579. XXrv_flash.c
  580. XXrv_forback.c
  581. XXrv_getline.c
  582. XXrv_init.c
  583. XXrv_input.c
  584. XXrv_insert.c
  585. XXrv_join.c
  586. XXrv_linecmd.c
  587. XXrv_main.c
  588. XXrv_mark.c
  589. XXrv_misc.c
  590. XXrv_move.c
  591. XXrv_openline.c
  592. XXrv_print_ln.c
  593. XXrv_put.c
  594. XXrv_quit.c
  595. XXrv_redraw.c
  596. XXrv_redraw_ln.c
  597. XXrv_scroll.c
  598. XXrv_scroll_bk.c
  599. XXrv_search.c
  600. XXrv_shell.c
  601. XXrv_sync.c
  602. XXrv_undo.c
  603. XXrv_where.c
  604. XXrv_word.c
  605. XXrv_xmit.c
  606. XXrv_yank.c
  607. XXrvi.1
  608. XXrvtest.c
  609. XXtodo
  610. XXzero.c
  611. @//E*O*F Manifest//
  612. chmod u=rw,g=rw,o=rw $OUT
  613.  
  614. echo x - regerror.c
  615. if test -f regerror.c ; then
  616.     echo regerror.c exists, putting output in $$regerror.c
  617.     OUT=$$regerror.c
  618.     STATUS=1
  619. else
  620.     OUT=regerror.c
  621. fi
  622. sed 's/^XX//' > $OUT <<'@//E*O*F regerror.c//'
  623. XX#include "rv.h"
  624.  
  625. XXvoid
  626. XXregerror(s)
  627. XXchar *s;
  628. XX{
  629. XX    botprint(TRUE, "%s", s);
  630. XX}
  631. @//E*O*F regerror.c//
  632. chmod u=rw,g=rw,o=rw $OUT
  633.  
  634. echo x - regexp.c
  635. if test -f regexp.c ; then
  636.     echo regexp.c exists, putting output in $$regexp.c
  637.     OUT=$$regexp.c
  638.     STATUS=1
  639. else
  640.     OUT=regexp.c
  641. fi
  642. sed 's/^XX//' > $OUT <<'@//E*O*F regexp.c//'
  643. XX#define RVI    /* Modified version for remote vi */
  644. XX#include <stdio.h>
  645.  
  646. XX#ifdef RVI
  647. XX#  if !defined(L_ctermid) || defined(sun)   /* If BSD system */
  648. XX#    define strchr index
  649. XX#    define STRCSPN
  650. XX#  endif
  651. XX#endif
  652. XX/*
  653. XX * regcomp and regexec -- regsub and regerror are elsewhere
  654. XX *
  655. XX *    Copyright (c) 1986 by University of Toronto.
  656. XX *    Written by Henry Spencer.  Not derived from licensed software.
  657. XX *
  658. XX *    Permission is granted to anyone to use this software for any
  659. XX *    purpose on any computer system, and to redistribute it freely,
  660. XX *    subject to the following restrictions:
  661. XX *
  662. XX *    1. The author is not responsible for the consequences of use of
  663. XX *        this software, no matter how awful, even if they arise
  664. XX *        from defects in it.
  665. XX *
  666. XX *    2. The origin of this software must not be misrepresented, either
  667. XX *        by explicit claim or by omission.
  668. XX *
  669. XX *    3. Altered versions must be plainly marked as such, and must not
  670. XX *        be misrepresented as being the original software.
  671. XX *
  672. XX * Beware that some of this code is subtly aware of the way operator
  673. XX * precedence is structured in regular expressions.  Serious changes in
  674. XX * regular-expression syntax might require a total rethink.
  675. XX */
  676. XX#include <stdio.h>
  677. XX#include "regexp.h"
  678. XX#include "regmagic.h"
  679.  
  680. XX/*
  681. XX * The "internal use only" fields in regexp.h are present to pass info from
  682. XX * compile to execute that permits the execute phase to run lots faster on
  683. XX * simple cases.  They are:
  684. XX *
  685. XX * regstart    char that must begin a match; '\0' if none obvious
  686. XX * reganch    is the match anchored (at beginning-of-line only)?
  687. XX * regmust    string (pointer into program) that match must include, or NULL
  688. XX * regmlen    length of regmust string
  689. XX *
  690. XX * Regstart and reganch permit very fast decisions on suitable starting points
  691. XX * for a match, cutting down the work a lot.  Regmust permits fast rejection
  692. XX * of lines that cannot possibly match.  The regmust tests are costly enough
  693. XX * that regcomp() supplies a regmust only if the r.e. contains something
  694. XX * potentially expensive (at present, the only such thing detected is * or +
  695. XX * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  696. XX * supplied because the test in regexec() needs it and regcomp() is computing
  697. XX * it anyway.
  698. XX */
  699.  
  700. XX/*
  701. XX * Structure for regexp "program".  This is essentially a linear encoding
  702. XX * of a nondeterministic finite-state machine (aka syntax charts or
  703. XX * "railroad normal form" in parsing technology).  Each node is an opcode
  704. XX * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  705. XX * all nodes except BRANCH implement concatenation; a "next" pointer with
  706. XX * a BRANCH on both ends of it is connecting two alternatives.  (Here we
  707. XX * have one of the subtle syntax dependencies:  an individual BRANCH (as
  708. XX * opposed to a collection of them) is never concatenated with anything
  709. XX * because of operator precedence.)  The operand of some types of node is
  710. XX * a literal string; for others, it is a node leading into a sub-FSM.  In
  711. XX * particular, the operand of a BRANCH node is the first node of the branch.
  712. XX * (NB this is *not* a tree structure:  the tail of the branch connects
  713. XX * to the thing following the set of BRANCHes.)  The opcodes are:
  714. XX */
  715.  
  716. XX/* definition    number    opnd?    meaning */
  717. XX#define    END    0    /* no    End of program. */
  718. XX#define    BOL    1    /* no    Match "" at beginning of line. */
  719. XX#define    EOL    2    /* no    Match "" at end of line. */
  720. XX#define    ANY    3    /* no    Match any one character. */
  721. XX#define    ANYOF    4    /* str    Match any character in this string. */
  722. XX#define    ANYBUT    5    /* str    Match any character not in this string. */
  723. XX#define    BRANCH    6    /* node    Match this alternative, or the next... */
  724. XX#define    BACK    7    /* no    Match "", "next" ptr points backward. */
  725. XX#define    EXACTLY    8    /* str    Match this string. */
  726. XX#define    NOTHING    9    /* no    Match empty string. */
  727. XX#define    STAR    10    /* node    Match this (simple) thing 0 or more times. */
  728. XX#define    PLUS    11    /* node    Match this (simple) thing 1 or more times. */
  729. XX#define    OPEN    20    /* no    Mark this point in input as start of #n. */
  730. XX            /*    OPEN+1 is number 1, etc. */
  731. XX#define    CLOSE    30    /* no    Analogous to OPEN. */
  732.  
  733. XX/*
  734. XX * Opcode notes:
  735. XX *
  736. XX * BRANCH    The set of branches constituting a single choice are hooked
  737. XX *        together with their "next" pointers, since precedence prevents
  738. XX *        anything being concatenated to any individual branch.  The
  739. XX *        "next" pointer of the last BRANCH in a choice points to the
  740. XX *        thing following the whole choice.  This is also where the
  741. XX *        final "next" pointer of each individual branch points; each
  742. XX *        branch starts with the operand node of a BRANCH node.
  743. XX *
  744. XX * BACK        Normal "next" pointers all implicitly point forward; BACK
  745. XX *        exists to make loop structures possible.
  746. XX *
  747. XX * STAR,PLUS    '?', and complex '*' and PLUSSIGN, are implemented as circular
  748. XX *        BRANCH structures using BACK.  Simple cases (one character
  749. XX *        per match) are implemented with STAR and PLUS for speed
  750. XX *        and to minimize recursive plunges.
  751. XX *
  752. XX * OPEN,CLOSE    ...are numbered at compile time.
  753. XX */
  754.  
  755. XX/*
  756. XX * A node is one char of opcode followed by two chars of "next" pointer.
  757. XX * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  758. XX * value is a positive offset from the opcode of the node containing it.
  759. XX * An operand, if any, simply follows the node.  (Note that much of the
  760. XX * code generation knows about this implicit relationship.)
  761. XX *
  762. XX * Using two bytes for the "next" pointer is vast overkill for most things,
  763. XX * but allows patterns to get big without disasters.
  764. XX */
  765. XX#define    OP(p)    (*(p))
  766. XX#define    NEXT(p)    (((*((p)+1)&0377)<<8) + *((p)+2)&0377)
  767. XX#define    OPERAND(p)    ((p) + 3)
  768.  
  769. XX/*
  770. XX * See regmagic.h for one further detail of program structure.
  771. XX */
  772.  
  773.  
  774. XX/*
  775. XX * Utility definitions.
  776. XX */
  777. XX#ifndef CHARBITS
  778. XX#define    UCHARAT(p)    ((int)*(unsigned char *)(p))
  779. XX#else
  780. XX#define    UCHARAT(p)    ((int)*(p)&CHARBITS)
  781. XX#endif
  782.  
  783. XX#define    FAIL(m)    { regerror(m); return(NULL); }
  784. XX#define    ISMULT(c)    ((c) == '*' || (c) == PLUSSIGN || (c) == '?')
  785.  
  786. XX#ifndef RVI     /* Original version */
  787. XX#define    META    "^$.[()|+*\\"
  788. XX#define LPAREN    '('
  789. XX#define RPAREN    ')'
  790. XX#define BAR    '|'
  791. XX#define PLUSSIGN '+'
  792. XX#define QUES    '?'
  793. XX#else       /* Modified version for rvi */
  794. XX#define META    "^$.[?*\\"
  795. XX#define LPAREN    255
  796. XX#define RPAREN    254
  797. XX#define BAR    253
  798. XX#define PLUSSIGN 252
  799. XX#define    QUES    251
  800. XX#endif
  801.  
  802. XX/*
  803. XX * Flags to be passed up and down.
  804. XX */
  805. XX#define    HASWIDTH    01    /* Known never to match null string. */
  806. XX#define    SIMPLE        02    /* Simple enough to be STAR/PLUS operand. */
  807. XX#define    SPSTART        04    /* Starts with * or +. */
  808. XX#define    WORST        0    /* Worst case. */
  809.  
  810. XX/*
  811. XX * Global work variables for regcomp().
  812. XX */
  813. XXstatic char *regparse;        /* Input-scan pointer. */
  814. XXstatic int regnpar;        /* () count. */
  815. XXstatic char regdummy;
  816. XXstatic char *regcode;        /* Code-emit pointer; ®dummy = don't. */
  817. XXstatic long regsize;        /* Code size. */
  818.  
  819. XX/*
  820. XX * Forward declarations for regcomp()'s friends.
  821. XX */
  822. XX#ifndef STATIC
  823. XX#define    STATIC    static
  824. XX#endif
  825. XXSTATIC char *reg();
  826. XXSTATIC char *regbranch();
  827. XXSTATIC char *regpiece();
  828. XXSTATIC char *regatom();
  829. XXSTATIC char *regnode();
  830. XXSTATIC char *regnext();
  831. XXSTATIC void regc();
  832. XXSTATIC void reginsert();
  833. XXSTATIC void regtail();
  834. XXSTATIC void regoptail();
  835. XX#ifdef STRCSPN
  836. XXSTATIC int strcspn();
  837. XX#endif
  838.  
  839. XX/*
  840. XX - regcomp - compile a regular expression into internal code
  841. XX *
  842. XX * We can't allocate space until we know how big the compiled form will be,
  843. XX * but we can't compile it (and thus know how big it is) until we've got a
  844. XX * place to put the code.  So we cheat:  we compile it twice, once with code
  845. XX * generation turned off and size counting turned on, and once "for real".
  846. XX * This also means that we don't allocate space until we are sure that the
  847. XX * thing really will compile successfully, and we never have to move the
  848. XX * code and thus invalidate pointers into it.  (Note that it has to be in
  849. XX * one piece because free() must be able to free it all.)
  850. XX *
  851. XX * Beware that the optimization-preparation code in here knows about some
  852. XX * of the structure of the compiled regexp.
  853. XX */
  854. XXregexp *
  855. XXregcomp(exp)
  856. XXchar *exp;
  857. XX{
  858. XX    register regexp *r;
  859. XX    register char *scan;
  860. XX    register char *longest;
  861. XX    register int len;
  862. XX    int flags;
  863. XX    extern char *malloc();
  864.  
  865. XX    if (exp == NULL)
  866. XX        FAIL("NULL argument");
  867.  
  868. XX    /* First pass: determine size, legality. */
  869. XX    regparse = exp;
  870. XX    regnpar = 1;
  871. XX    regsize = 0L;
  872. XX    regcode = ®dummy;
  873. XX    regc(MAGIC);
  874. XX    if (reg(0, &flags) == NULL)
  875. XX        return(NULL);
  876.  
  877. XX    /* Small enough for pointer-storage convention? */
  878. XX    if (regsize >= 32767L)        /* Probably could be 65535L. */
  879. XX        FAIL("regexp too big");
  880.  
  881. XX    /* Allocate space. */
  882. XX    r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
  883. XX    if (r == NULL)
  884. XX        FAIL("out of space");
  885.  
  886. XX    /* Second pass: emit code. */
  887. XX    regparse = exp;
  888. XX    regnpar = 1;
  889. XX    regcode = r->program;
  890. XX    regc(MAGIC);
  891. XX    if (reg(0, &flags) == NULL)
  892. XX        return(NULL);
  893.  
  894. XX    /* Dig out information for optimizations. */
  895. XX    r->regstart = '\0';    /* Worst-case defaults. */
  896. XX    r->reganch = 0;
  897. XX    r->regmust = NULL;
  898. XX    r->regmlen = 0;
  899. XX    scan = r->program+1;            /* First BRANCH. */
  900. XX    if (OP(regnext(scan)) == END) {        /* Only one top-level choice. */
  901. XX        scan = OPERAND(scan);
  902.  
  903. XX        /* Starting-point info. */
  904. XX        if (OP(scan) == EXACTLY)
  905. XX            r->regstart = *OPERAND(scan);
  906. XX        else if (OP(scan) == BOL)
  907. XX            r->reganch++;
  908.  
  909. XX        /*
  910. XX         * If there's something expensive in the r.e., find the
  911. XX         * longest literal string that must appear and make it the
  912. XX         * regmust.  Resolve ties in favor of later strings, since
  913. XX         * the regstart check works with the beginning of the r.e.
  914. XX         * and avoiding duplication strengthens checking.  Not a
  915. XX         * strong reason, but sufficient in the absence of others.
  916. XX         */
  917. XX        if (flags&SPSTART) {
  918. XX            longest = NULL;
  919. XX            len = 0;
  920. XX            for (; scan != NULL; scan = regnext(scan))
  921. XX                if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  922. XX                    longest = OPERAND(scan);
  923. XX                    len = strlen(OPERAND(scan));
  924. XX                }
  925. XX            r->regmust = longest;
  926. XX            r->regmlen = len;
  927. XX        }
  928. XX    }
  929.  
  930. XX    return(r);
  931. XX}
  932.  
  933. XX/*
  934. XX - reg - regular expression, i.e. main body or parenthesized thing
  935. XX *
  936. XX * Caller must absorb opening parenthesis.
  937. XX *
  938. XX * Combining parenthesis handling with the base level of regular expression
  939. XX * is a trifle forced, but the need to tie the tails of the branches to what
  940. XX * follows makes it hard to avoid.
  941. XX */
  942. XXstatic char *
  943. XXreg(paren, flagp)
  944. XXint paren;            /* Parenthesized? */
  945. XXint *flagp;
  946. XX{
  947. XX    register char *ret;
  948. XX    register char *br;
  949. XX    register char *ender;
  950. XX    register int parno;
  951. XX    int flags;
  952.  
  953. XX    *flagp = HASWIDTH;    /* Tentatively. */
  954.  
  955. XX    /* Make an OPEN node, if parenthesized. */
  956. XX    if (paren) {
  957. XX        if (regnpar >= NSUBEXP)
  958. XX            FAIL("too many ()");
  959. XX        parno = regnpar;
  960. XX        regnpar++;
  961. XX        ret = regnode(OPEN+parno);
  962. XX    } else
  963. XX        ret = NULL;
  964.  
  965. XX    /* Pick up the branches, linking them together. */
  966. XX    br = regbranch(&flags);
  967. XX    if (br == NULL)
  968. XX        return(NULL);
  969. XX    if (ret != NULL)
  970. XX        regtail(ret, br);    /* OPEN -> first. */
  971. XX    else
  972. XX        ret = br;
  973. XX    if (!(flags&HASWIDTH))
  974. XX        *flagp &= ~HASWIDTH;
  975. XX    *flagp |= flags&SPSTART;
  976. XX    while (*regparse == BAR) {
  977. XX        regparse++;
  978. XX        br = regbranch(&flags);
  979. XX        if (br == NULL)
  980. XX            return(NULL);
  981. XX        regtail(ret, br);    /* BRANCH -> BRANCH. */
  982. XX        if (!(flags&HASWIDTH))
  983. XX            *flagp &= ~HASWIDTH;
  984. XX        *flagp |= flags&SPSTART;
  985. XX    }
  986.  
  987. XX    /* Make a closing node, and hook it on the end. */
  988. XX    ender = regnode((paren) ? CLOSE+parno : END);    
  989. XX    regtail(ret, ender);
  990.  
  991. XX    /* Hook the tails of the branches to the closing node. */
  992. XX    for (br = ret; br != NULL; br = regnext(br))
  993. XX        regoptail(br, ender);
  994.  
  995. XX    /* Check for proper termination. */
  996. XX    if (paren && *regparse++ != RPAREN) {
  997. XX        FAIL("unmatched ()");
  998. XX    } else if (!paren && *regparse != '\0') {
  999. XX        if (*regparse == RPAREN) {
  1000. XX            FAIL("unmatched ()");
  1001. XX        } else
  1002. XX            FAIL("junk on end");    /* "Can't happen". */
  1003. XX        /* NOTREACHED */
  1004. XX    }
  1005.  
  1006. XX    return(ret);
  1007. XX}
  1008.  
  1009. XX/*
  1010. XX - regbranch - one alternative of an | operator
  1011. XX *
  1012. XX * Implements the concatenation operator.
  1013. XX */
  1014. XXstatic char *
  1015. XXregbranch(flagp)
  1016. XXint *flagp;
  1017. XX{
  1018. XX    register char *ret;
  1019. XX    register char *chain;
  1020. XX    register char *latest;
  1021. XX    int flags;
  1022.  
  1023. XX    *flagp = WORST;        /* Tentatively. */
  1024.  
  1025. XX    ret = regnode(BRANCH);
  1026. XX    chain = NULL;
  1027. XX    while (*regparse != '\0' && *regparse != BAR && *regparse != RPAREN) {
  1028. XX        latest = regpiece(&flags);
  1029. XX        if (latest == NULL)
  1030. XX            return(NULL);
  1031. XX        *flagp |= flags&HASWIDTH;
  1032. XX        if (chain == NULL)    /* First piece. */
  1033. XX            *flagp |= flags&SPSTART;
  1034. XX        else
  1035. XX            regtail(chain, latest);
  1036. XX        chain = latest;
  1037. XX    }
  1038. XX    if (chain == NULL)    /* Loop ran zero times. */
  1039. XX        (void) regnode(NOTHING);
  1040.  
  1041. XX    return(ret);
  1042. XX}
  1043.  
  1044. XX/*
  1045. XX - regpiece - something followed by possible [*+?]
  1046. XX *
  1047. XX * Note that the branching code sequences used for ? and the general cases
  1048. XX * of * and + are somewhat optimized:  they use the same NOTHING node as
  1049. XX * both the endmarker for their branch list and the body of the last branch.
  1050. XX * It might seem that this node could be dispensed with entirely, but the
  1051. XX * endmarker role is not redundant.
  1052. XX */
  1053. XXstatic char *
  1054. XXregpiece(flagp)
  1055. XXint *flagp;
  1056. XX{
  1057. XX    register char *ret;
  1058. XX    register char op;
  1059. XX    register char *next;
  1060. XX    int flags;
  1061.  
  1062. XX    ret = regatom(&flags);
  1063. XX    if (ret == NULL)
  1064. XX        return(NULL);
  1065.  
  1066. XX    op = *regparse;
  1067. XX    if (!ISMULT(op)) {
  1068. XX        *flagp = flags;
  1069. XX        return(ret);
  1070. XX    }
  1071.  
  1072. XX    if (!(flags&HASWIDTH) && op != '?')
  1073. XX        FAIL("*+ operand could be empty");
  1074. XX    *flagp = (op != PLUSSIGN) ? (WORST|SPSTART) : (WORST|HASWIDTH);
  1075.  
  1076. XX    if (op == '*' && (flags&SIMPLE))
  1077. XX        reginsert(STAR, ret);
  1078. XX    else if (op == '*') {
  1079. XX        /* Emit x* as (x&|), where & means "self". */
  1080. XX        reginsert(BRANCH, ret);            /* Either x */
  1081. XX        regoptail(ret, regnode(BACK));        /* and loop */
  1082. XX        regoptail(ret, ret);            /* back */
  1083. XX        regtail(ret, regnode(BRANCH));        /* or */
  1084. XX        regtail(ret, regnode(NOTHING));        /* null. */
  1085. XX    } else if (op == PLUSSIGN && (flags&SIMPLE))
  1086. XX        reginsert(PLUS, ret);
  1087. XX    else if (op == PLUSSIGN) {
  1088. XX        /* Emit x+ as x(&|), where & means "self". */
  1089. XX        next = regnode(BRANCH);            /* Either */
  1090. XX        regtail(ret, next);
  1091. XX        regtail(regnode(BACK), ret);        /* loop back */
  1092. XX        regtail(next, regnode(BRANCH));        /* or */
  1093. XX        regtail(ret, regnode(NOTHING));        /* null. */
  1094. XX    } else if (op == '?') {
  1095. XX        /* Emit x? as (x|) */
  1096. XX        reginsert(BRANCH, ret);            /* Either x */
  1097. XX        regtail(ret, regnode(BRANCH));        /* or */
  1098. XX        next = regnode(NOTHING);        /* null. */
  1099. XX        regtail(ret, next);
  1100. XX        regoptail(ret, next);
  1101. XX    }
  1102. XX    regparse++;
  1103. XX    if (ISMULT(*regparse))
  1104. XX        FAIL("nested *?+");
  1105.  
  1106. XX    return(ret);
  1107. XX}
  1108.  
  1109. XX/*
  1110. XX - regatom - the lowest level
  1111. XX *
  1112. XX * Optimization:  gobbles an entire sequence of ordinary characters so that
  1113. XX * it can turn them into a single node, which is smaller to store and
  1114. XX * faster to run.  Backslashed characters are exceptions, each becoming a
  1115. XX * separate node; the code is simpler that way and it's not worth fixing.
  1116. XX */
  1117. XXstatic char *
  1118. XXregatom(flagp)
  1119. XXint *flagp;
  1120. XX{
  1121. XX    register char *ret;
  1122. XX    int flags;
  1123.  
  1124. XX    *flagp = WORST;        /* Tentatively. */
  1125.  
  1126. XX    switch (*regparse++) {
  1127. XX    case '^':
  1128. XX        ret = regnode(BOL);
  1129. XX        break;
  1130. XX    case '$':
  1131. XX        ret = regnode(EOL);
  1132. XX        break;
  1133. XX    case '.':
  1134. XX        ret = regnode(ANY);
  1135. XX        *flagp |= HASWIDTH|SIMPLE;
  1136. XX        break;
  1137. XX    case '[': {
  1138. XX            register int class;
  1139. XX            register int classend;
  1140.  
  1141. XX            if (*regparse == '^') {    /* Complement of range. */
  1142. XX                ret = regnode(ANYBUT);
  1143. XX                regparse++;
  1144. XX            } else
  1145. XX                ret = regnode(ANYOF);
  1146. XX            if (*regparse == ']' || *regparse == '-')
  1147. XX                regc(*regparse++);
  1148. XX            while (*regparse != '\0' && *regparse != ']') {
  1149. XX                if (*regparse == '-') {
  1150. XX                    regparse++;
  1151. XX                    if (*regparse == ']' || *regparse == '\0')
  1152. XX                        regc('-');
  1153. XX                    else {
  1154. XX                        class = UCHARAT(regparse-2)+1;
  1155. XX                        classend = UCHARAT(regparse);
  1156. XX                        if (class > classend+1)
  1157. XX                            FAIL("invalid [] range");
  1158. XX                        for (; class <= classend; class++)
  1159. XX                            regc(class);
  1160. XX                        regparse++;
  1161. XX                    }
  1162. XX                } else
  1163. XX                    regc(*regparse++);
  1164. XX            }
  1165. XX            regc('\0');
  1166. XX            if (*regparse != ']')
  1167. XX                FAIL("unmatched []");
  1168. XX            regparse++;
  1169. XX            *flagp |= HASWIDTH|SIMPLE;
  1170. XX        }
  1171. XX        break;
  1172. XX    case LPAREN:
  1173. XX        ret = reg(1, &flags);
  1174. XX        if (ret == NULL)
  1175. XX            return(NULL);
  1176. XX        *flagp |= flags&(HASWIDTH|SPSTART);
  1177. XX        break;
  1178. XX    case '\0':
  1179. XX    case BAR:
  1180. XX    case RPAREN:
  1181. XX        FAIL("internal urp");    /* Supposed to be caught earlier. */
  1182. XX        break;
  1183. XX    case '?':
  1184. XX    case PLUSSIGN:
  1185. XX    case '*':
  1186. XX        FAIL("?+* follows nothing");
  1187. XX        break;
  1188. XX    case '\\':
  1189. XX        if (*regparse == '\0')
  1190. XX            FAIL("trailing \\");
  1191. XX        ret = regnode(EXACTLY);
  1192. XX        regc(*regparse++);
  1193. XX        regc('\0');
  1194. XX        *flagp |= HASWIDTH|SIMPLE;
  1195. XX        break;
  1196. XX    default: {
  1197. XX            register int len;
  1198. XX            register char ender;
  1199.  
  1200. XX            regparse--;
  1201. XX            len = strcspn(regparse, META);
  1202. XX            if (len <= 0)
  1203. XX                FAIL("internal disaster");
  1204. XX            ender = *(regparse+len);
  1205. XX            if (len > 1 && ISMULT(ender))
  1206. XX                len--;        /* Back off clear of ?+* operand. */
  1207. XX            *flagp |= HASWIDTH;
  1208. XX            if (len == 1)
  1209. XX                *flagp |= SIMPLE;
  1210. XX            ret = regnode(EXACTLY);
  1211. XX            while (len > 0) {
  1212. XX                regc(*regparse++);
  1213. XX                len--;
  1214. XX            }
  1215. XX            regc('\0');
  1216. XX        }
  1217. XX        break;
  1218. XX    }
  1219.  
  1220. XX    return(ret);
  1221. XX}
  1222.  
  1223. XX/*
  1224. XX - regnode - emit a node
  1225. XX */
  1226. XXstatic char *            /* Location. */
  1227. XXregnode(op)
  1228. XXchar op;
  1229. XX{
  1230. XX    register char *ret;
  1231. XX    register char *ptr;
  1232.  
  1233. XX    ret = regcode;
  1234. XX    if (ret == ®dummy) {
  1235. XX        regsize += 3;
  1236. XX        return(ret);
  1237. XX    }
  1238.  
  1239. XX    ptr = ret;
  1240. XX    *ptr++ = op;
  1241. XX    *ptr++ = '\0';        /* Null "next" pointer. */
  1242. XX    *ptr++ = '\0';
  1243. XX    regcode = ptr;
  1244.  
  1245. XX    return(ret);
  1246. XX}
  1247.  
  1248. XX/*
  1249. XX - regc - emit (if appropriate) a byte of code
  1250. XX */
  1251. XXstatic void
  1252. XXregc(b)
  1253. XXchar b;
  1254. XX{
  1255. XX    if (regcode != ®dummy)
  1256. XX        *regcode++ = b;
  1257. XX    else
  1258. XX        regsize++;
  1259. XX}
  1260.  
  1261. XX/*
  1262. XX - reginsert - insert an operator in front of already-emitted operand
  1263. XX *
  1264. XX * Means relocating the operand.
  1265. XX */
  1266. XXstatic void
  1267. XXreginsert(op, opnd)
  1268. XXchar op;
  1269. XXchar *opnd;
  1270. XX{
  1271. XX    register char *src;
  1272. XX    register char *dst;
  1273. XX    register char *place;
  1274.  
  1275. XX    if (regcode == ®dummy) {
  1276. XX        regsize += 3;
  1277. XX        return;
  1278. XX    }
  1279.  
  1280. XX    src = regcode;
  1281. XX    regcode += 3;
  1282. XX    dst = regcode;
  1283. XX    while (src > opnd)
  1284. XX        *--dst = *--src;
  1285.  
  1286. XX    place = opnd;        /* Op node, where operand used to be. */
  1287. XX    *place++ = op;
  1288. XX    *place++ = '\0';
  1289. XX    *place++ = '\0';
  1290. XX}
  1291.  
  1292. XX/*
  1293. XX - regtail - set the next-pointer at the end of a node chain
  1294. XX */
  1295. XXstatic void
  1296. XXregtail(p, val)
  1297. XXchar *p;
  1298. XXchar *val;
  1299. XX{
  1300. XX    register char *scan;
  1301. XX    register char *temp;
  1302. XX    register int offset;
  1303.  
  1304. XX    if (p == ®dummy)
  1305. XX        return;
  1306.  
  1307. XX    /* Find last node. */
  1308. XX    scan = p;
  1309. XX    for (;;) {
  1310. XX        temp = regnext(scan);
  1311. XX        if (temp == NULL)
  1312. XX            break;
  1313. XX        scan = temp;
  1314. XX    }
  1315.  
  1316. XX    if (OP(scan) == BACK)
  1317. XX        offset = scan - val;
  1318. XX    else
  1319. XX        offset = val - scan;
  1320. XX    *(scan+1) = (offset>>8)&0377;
  1321. XX    *(scan+2) = offset&0377;
  1322. XX}
  1323.  
  1324. XX/*
  1325. XX - regoptail - regtail on operand of first argument; nop if operandless
  1326. XX */
  1327. XXstatic void
  1328. XXregoptail(p, val)
  1329. XXchar *p;
  1330. XXchar *val;
  1331. XX{
  1332. XX    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  1333. XX    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  1334. XX        return;
  1335. XX    regtail(OPERAND(p), val);
  1336. XX}
  1337.  
  1338. XX/*
  1339. XX * regexec and friends
  1340. XX */
  1341.  
  1342. XX/*
  1343. XX * Global work variables for regexec().
  1344. XX */
  1345. XXstatic char *reginput;        /* String-input pointer. */
  1346. XXstatic char *regbol;        /* Beginning of input, for ^ check. */
  1347. XXstatic char **regstartp;    /* Pointer to startp array. */
  1348. XXstatic char **regendp;        /* Ditto for endp. */
  1349.  
  1350. XX/*
  1351. XX * Forwards.
  1352. XX */
  1353. XXSTATIC int regtry();
  1354. XXSTATIC int regmatch();
  1355. XXSTATIC int regrepeat();
  1356.  
  1357. XX#ifdef DEBUG
  1358. XXint regnarrate = 0;
  1359. XXvoid regdump();
  1360. XXSTATIC char *regprop();
  1361. XX#endif
  1362.  
  1363. XX/*
  1364. XX - regexec - match a regexp against a string
  1365. XX */
  1366. XXint
  1367. XXregexec(prog, string)
  1368. XXregister regexp *prog;
  1369. XXregister char *string;
  1370. XX{
  1371. XX    register char *s;
  1372. XX    extern char *strchr();
  1373.  
  1374. XX    /* Be paranoid... */
  1375. XX    if (prog == NULL || string == NULL) {
  1376. XX        regerror("NULL parameter");
  1377. XX        return(0);
  1378. XX    }
  1379.  
  1380. XX    /* Check validity of program. */
  1381. XX    if (UCHARAT(prog->program) != MAGIC) {
  1382. XX        regerror("corrupted program");
  1383. XX        return(0);
  1384. XX    }
  1385.  
  1386. XX    /* If there is a "must appear" string, look for it. */
  1387. XX    if (prog->regmust != NULL) {
  1388. XX        s = string;
  1389. XX        while ((s = strchr(s, prog->regmust[0])) != NULL) {
  1390. XX            if (strncmp(s, prog->regmust, prog->regmlen) == 0)
  1391. XX                break;    /* Found it. */
  1392. XX            s++;
  1393. XX        }
  1394. XX        if (s == NULL)    /* Not present. */
  1395. XX            return(0);
  1396. XX    }
  1397.  
  1398. XX    /* Mark beginning of line for ^ . */
  1399. XX    regbol = string;
  1400.  
  1401. XX    /* Simplest case:  anchored match need be tried only once. */
  1402. XX    if (prog->reganch)
  1403. XX        return(regtry(prog, string));
  1404.  
  1405. XX    /* Messy cases:  unanchored match. */
  1406. XX    s = string;
  1407. XX    if (prog->regstart != '\0')
  1408. XX        /* We know what char it must start with. */
  1409. XX        while ((s = strchr(s, prog->regstart)) != NULL) {
  1410. XX            if (regtry(prog, s))
  1411. XX                return(1);
  1412. XX            s++;
  1413. XX        }
  1414. XX    else
  1415. XX        /* We don't -- general case. */
  1416. XX        do {
  1417. XX            if (regtry(prog, s))
  1418. XX                return(1);
  1419. XX        } while (*s++ != '\0');
  1420.  
  1421. XX    /* Failure. */
  1422. XX    return(0);
  1423. XX}
  1424.  
  1425. XX/*
  1426. XX - regtry - try match at specific point
  1427. XX */
  1428. XXstatic int            /* 0 failure, 1 success */
  1429. XXregtry(prog, string)
  1430. XXregexp *prog;
  1431. XXchar *string;
  1432. XX{
  1433. XX    register int i;
  1434. XX    register char **sp;
  1435. XX    register char **ep;
  1436.  
  1437. XX    reginput = string;
  1438. XX    regstartp = prog->startp;
  1439. XX    regendp = prog->endp;
  1440.  
  1441. XX    sp = prog->startp;
  1442. XX    ep = prog->endp;
  1443. XX    for (i = NSUBEXP; i > 0; i--) {
  1444. XX        *sp++ = NULL;
  1445. XX        *ep++ = NULL;
  1446. XX    }
  1447. XX    if (regmatch(prog->program + 1)) {
  1448. XX        prog->startp[0] = string;
  1449. XX        prog->endp[0] = reginput;
  1450. XX        return(1);
  1451. XX    } else
  1452. XX        return(0);
  1453. XX}
  1454.  
  1455. XX/*
  1456. XX - regmatch - main matching routine
  1457. XX *
  1458. XX * Conceptually the strategy is simple:  check to see whether the current
  1459. XX * node matches, call self recursively to see whether the rest matches,
  1460. XX * and then act accordingly.  In practice we make some effort to avoid
  1461. XX * recursion, in particular by going through "ordinary" nodes (that don't
  1462. XX * need to know whether the rest of the match failed) by a loop instead of
  1463. XX * by recursion.
  1464. XX */
  1465. XXstatic int            /* 0 failure, 1 success */
  1466. XXregmatch(prog)
  1467. XXchar *prog;
  1468. XX{
  1469. XX    register char *scan;    /* Current node. */
  1470. XX    char *next;        /* Next node. */
  1471. XX    extern char *strchr();
  1472.  
  1473. XX    scan = prog;
  1474. XX#ifdef DEBUG
  1475. XX    if (scan != NULL && regnarrate)
  1476. XX        fprintf(stderr, "%s(\n", regprop(scan));
  1477. XX#endif
  1478. XX    while (scan != NULL) {
  1479. XX#ifdef DEBUG
  1480. XX        if (regnarrate)
  1481. XX            fprintf(stderr, "%s...\n", regprop(scan));
  1482. XX#endif
  1483. XX        next = regnext(scan);
  1484.  
  1485. XX        switch (OP(scan)) {
  1486. XX        case BOL:
  1487. XX            if (reginput != regbol)
  1488. XX                return(0);
  1489. XX            break;
  1490. XX        case EOL:
  1491. XX            if (*reginput != '\0')
  1492. XX                return(0);
  1493. XX            break;
  1494. XX        case ANY:
  1495. XX            if (*reginput == '\0')
  1496. XX                return(0);
  1497. XX            reginput++;
  1498. XX            break;
  1499. XX        case EXACTLY: {
  1500. XX                register int len;
  1501. XX                register char *opnd;
  1502.  
  1503. XX                opnd = OPERAND(scan);
  1504. XX                /* Inline the first character, for speed. */
  1505. XX                if (*opnd != *reginput)
  1506. XX                    return(0);
  1507. XX                len = strlen(opnd);
  1508. XX                if (len > 1 && strncmp(opnd, reginput, len) != 0)
  1509. XX                    return(0);
  1510. XX                reginput += len;
  1511. XX            }
  1512. XX            break;
  1513. XX        case ANYOF:
  1514. XX            if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  1515. XX                return(0);
  1516. XX            reginput++;
  1517. XX            break;
  1518. XX        case ANYBUT:
  1519. XX            if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  1520. XX                return(0);
  1521. XX            reginput++;
  1522. XX            break;
  1523. XX        case NOTHING:
  1524. XX            break;
  1525. XX        case BACK:
  1526. XX            break;
  1527. XX        case OPEN+1:
  1528. XX        case OPEN+2:
  1529. XX        case OPEN+3:
  1530. XX        case OPEN+4:
  1531. XX        case OPEN+5:
  1532. XX        case OPEN+6:
  1533. XX        case OPEN+7:
  1534. XX        case OPEN+8:
  1535. XX        case OPEN+9: {
  1536. XX                register int no;
  1537. XX                register char *save;
  1538.  
  1539. XX                no = OP(scan) - OPEN;
  1540. XX                save = reginput;
  1541.  
  1542. XX                if (regmatch(next)) {
  1543. XX                    /*
  1544. XX                     * Don't set startp if some later
  1545. XX                     * invocation of the same parentheses
  1546. XX                     * already has.
  1547. XX                     */
  1548. XX                    if (regstartp[no] == NULL)
  1549. XX                        regstartp[no] = save;
  1550. XX                    return(1);
  1551. XX                } else
  1552. XX                    return(0);
  1553. XX            }
  1554. XX            break;
  1555. XX        case CLOSE+1:
  1556. XX        case CLOSE+2:
  1557. XX        case CLOSE+3:
  1558. XX        case CLOSE+4:
  1559. XX        case CLOSE+5:
  1560. XX        case CLOSE+6:
  1561. XX        case CLOSE+7:
  1562. XX        case CLOSE+8:
  1563. XX        case CLOSE+9: {
  1564. XX                register int no;
  1565. XX                register char *save;
  1566.  
  1567. XX                no = OP(scan) - CLOSE;
  1568. XX                save = reginput;
  1569.  
  1570. XX                if (regmatch(next)) {
  1571. XX                    /*
  1572. XX                     * Don't set endp if some later
  1573. XX                     * invocation of the same parentheses
  1574. XX                     * already has.
  1575. XX                     */
  1576. XX                    if (regendp[no] == NULL)
  1577. XX                        regendp[no] = save;
  1578. XX                    return(1);
  1579. XX                } else
  1580. XX                    return(0);
  1581. XX            }
  1582. XX            break;
  1583. XX        case BRANCH: {
  1584. XX                register char *save;
  1585.  
  1586. XX                if (OP(next) != BRANCH)        /* No choice. */
  1587. XX                    next = OPERAND(scan);    /* Avoid recursion. */
  1588. XX                else {
  1589. XX                    do {
  1590. XX                        save = reginput;
  1591. XX                        if (regmatch(OPERAND(scan)))
  1592. XX                            return(1);
  1593. XX                        reginput = save;
  1594. XX                        scan = regnext(scan);
  1595. XX                    } while (scan != NULL && OP(scan) == BRANCH);
  1596. XX                    return(0);
  1597. XX                    /* NOTREACHED */
  1598. XX                }
  1599. XX            }
  1600. XX            break;
  1601. XX        case STAR:
  1602. XX        case PLUS: {
  1603. XX                register char nextch;
  1604. XX                register int no;
  1605. XX                register char *save;
  1606. XX                register int min;
  1607.  
  1608. XX                /*
  1609. XX                 * Lookahead to avoid useless match attempts
  1610. XX                 * when we know what character comes next.
  1611. XX                 */
  1612. XX                nextch = '\0';
  1613. XX                if (OP(next) == EXACTLY)
  1614. XX                    nextch = *OPERAND(next);
  1615. XX                min = (OP(scan) == STAR) ? 0 : 1;
  1616. XX                save = reginput;
  1617. XX                no = regrepeat(OPERAND(scan));
  1618. XX                while (no >= min) {
  1619. XX                    /* If it could work, try it. */
  1620. XX                    if (nextch == '\0' || *reginput == nextch)
  1621. XX                        if (regmatch(next))
  1622. XX                            return(1);
  1623. XX                    /* Couldn't or didn't -- back up. */
  1624. XX                    no--;
  1625. XX                    reginput = save + no;
  1626. XX                }
  1627. XX                return(0);
  1628. XX            }
  1629. XX            break;
  1630. XX        case END:
  1631. XX            return(1);    /* Success! */
  1632. XX            break;
  1633. XX        default:
  1634. XX            regerror("memory corruption");
  1635. XX            return(0);
  1636. XX            break;
  1637. XX        }
  1638.  
  1639. XX        scan = next;
  1640. XX    }
  1641.  
  1642. XX    /*
  1643. XX     * We get here only if there's trouble -- normally "case END" is
  1644. XX     * the terminating point.
  1645. XX     */
  1646. XX    regerror("corrupted pointers");
  1647. XX    return(0);
  1648. XX}
  1649.  
  1650. XX/*
  1651. XX - regrepeat - repeatedly match something simple, report how many
  1652. XX */
  1653. XXstatic int
  1654. XXregrepeat(p)
  1655. XXchar *p;
  1656. XX{
  1657. XX    register int count = 0;
  1658. XX    register char *scan;
  1659. XX    register char *opnd;
  1660.  
  1661. XX    scan = reginput;
  1662. XX    opnd = OPERAND(p);
  1663. XX    switch (OP(p)) {
  1664. XX    case ANY:
  1665. XX        count = strlen(scan);
  1666. XX        scan += count;
  1667. XX        break;
  1668. XX    case EXACTLY:
  1669. XX        while (*opnd == *scan) {
  1670. XX            count++;
  1671. XX            scan++;
  1672. XX        }
  1673. XX        break;
  1674. XX    case ANYOF:
  1675. XX        while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  1676. XX            count++;
  1677. XX            scan++;
  1678. XX        }
  1679. XX        break;
  1680. XX    case ANYBUT:
  1681. XX        while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  1682. XX            count++;
  1683. XX            scan++;
  1684. XX        }
  1685. XX        break;
  1686. XX    default:        /* Oh dear.  Called inappropriately. */
  1687. XX        regerror("internal foulup");
  1688. XX        count = 0;    /* Best compromise. */
  1689. XX        break;
  1690. XX    }
  1691. XX    reginput = scan;
  1692.  
  1693. XX    return(count);
  1694. XX}
  1695.  
  1696. XX/*
  1697. XX - regnext - dig the "next" pointer out of a node
  1698. XX */
  1699. XXstatic char *
  1700. XXregnext(p)
  1701. XXregister char *p;
  1702. XX{
  1703. XX    register int offset;
  1704.  
  1705. XX    if (p == ®dummy)
  1706. XX        return(NULL);
  1707.  
  1708. XX    offset = NEXT(p);
  1709. XX    if (offset == 0)
  1710. XX        return(NULL);
  1711.  
  1712. XX    if (OP(p) == BACK)
  1713. XX        return(p-offset);
  1714. XX    else
  1715. XX        return(p+offset);
  1716. XX}
  1717.  
  1718. XX#ifdef DEBUG
  1719.  
  1720. XXSTATIC char *regprop();
  1721.  
  1722. XX/*
  1723. XX - regdump - dump a regexp onto stdout in vaguely comprehensible form
  1724. XX */
  1725. XXvoid
  1726. XXregdump(r)
  1727. XXregexp *r;
  1728. XX{
  1729. XX    register char *s;
  1730. XX    register char op = EXACTLY;    /* Arbitrary non-END op. */
  1731. XX    register char *next;
  1732. XX    extern char *strchr();
  1733.  
  1734.  
  1735. XX    s = r->program + 1;
  1736. XX    while (op != END) {    /* While that wasn't END last time... */
  1737. XX        op = OP(s);
  1738. XX        printf("%2d%s", s-r->program, regprop(s));    /* Where, what. */
  1739. XX        next = regnext(s);
  1740. XX        if (next == NULL)        /* Next ptr. */
  1741. XX            printf("(0)");
  1742. XX        else 
  1743. XX            printf("(%d)", (s-r->program)+(next-s));
  1744. XX        s += 3;
  1745. XX        if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  1746. XX            /* Literal string, where present. */
  1747. XX            while (*s != '\0') {
  1748. XX                putchar(*s);
  1749. XX                s++;
  1750. XX            }
  1751. XX            s++;
  1752. XX        }
  1753. XX        putchar('\n');
  1754. XX    }
  1755.  
  1756. XX    /* Header fields of interest. */
  1757. XX    if (r->regstart != '\0')
  1758. XX        printf("start `%c' ", r->regstart);
  1759. XX    if (r->reganch)
  1760. XX        printf("anchored ");
  1761. XX    if (r->regmust != NULL)
  1762. XX        printf("must have \"%s\"", r->regmust);
  1763. XX    printf("\n");
  1764. XX}
  1765.  
  1766. XX/*
  1767. XX - regprop - printable representation of opcode
  1768. XX */
  1769. XXstatic char *
  1770. XXregprop(op)
  1771. XXchar *op;
  1772. XX{
  1773. XX    register char *p;
  1774. XX    static char buf[50];
  1775.  
  1776. XX    (void) strcpy(buf, ":");
  1777.  
  1778. XX    switch (OP(op)) {
  1779. XX    case BOL:
  1780. XX        p = "BOL";
  1781. XX        break;
  1782. XX    case EOL:
  1783. XX        p = "EOL";
  1784. XX        break;
  1785. XX    case ANY:
  1786. XX        p = "ANY";
  1787. XX        break;
  1788. XX    case ANYOF:
  1789. XX        p = "ANYOF";
  1790. XX        break;
  1791. XX    case ANYBUT:
  1792. XX        p = "ANYBUT";
  1793. XX        break;
  1794. XX    case BRANCH:
  1795. XX        p = "BRANCH";
  1796. XX        break;
  1797. XX    case EXACTLY:
  1798. XX        p = "EXACTLY";
  1799. XX        break;
  1800. XX    case NOTHING:
  1801. XX        p = "NOTHING";
  1802. XX        break;
  1803. XX    case BACK:
  1804. XX        p = "BACK";
  1805. XX        break;
  1806. XX    case END:
  1807. XX        p = "END";
  1808. XX        break;
  1809. XX    case OPEN+1:
  1810. XX    case OPEN+2:
  1811. XX    case OPEN+3:
  1812. XX    case OPEN+4:
  1813. XX    case OPEN+5:
  1814. XX    case OPEN+6:
  1815. XX    case OPEN+7:
  1816. XX    case OPEN+8:
  1817. XX    case OPEN+9:
  1818. XX        sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
  1819. XX        p = NULL;
  1820. XX        break;
  1821. XX    case CLOSE+1:
  1822. XX    case CLOSE+2:
  1823. XX    case CLOSE+3:
  1824. XX    case CLOSE+4:
  1825. XX    case CLOSE+5:
  1826. XX    case CLOSE+6:
  1827. XX    case CLOSE+7:
  1828. XX    case CLOSE+8:
  1829. XX    case CLOSE+9:
  1830. XX        sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
  1831. XX        p = NULL;
  1832. XX        break;
  1833. XX    case STAR:
  1834. XX        p = "STAR";
  1835. XX        break;
  1836. XX    case PLUS:
  1837. XX        p = "PLUS";
  1838. XX        break;
  1839. XX    default:
  1840. XX        regerror("corrupted opcode");
  1841. XX        break;
  1842. XX    }
  1843. XX    if (p != NULL)
  1844. XX        (void) strcat(buf, p);
  1845. XX    return(buf);
  1846. XX}
  1847. XX#endif
  1848.  
  1849. XX/*
  1850. XX * The following is provided for those people who do not have strcspn() in
  1851. XX * their C libraries.  They should get off their butts and do something
  1852. XX * about it; at least one public-domain implementation of those (highly
  1853. XX * useful) string routines has been published on Usenet.
  1854. XX */
  1855. XX#ifdef STRCSPN
  1856. XX/*
  1857. XX * strcspn - find length of initial segment of s1 consisting entirely
  1858. XX * of characters not from s2
  1859. XX */
  1860.  
  1861. XXstatic int
  1862. XXstrcspn(s1, s2)
  1863. XXchar *s1;
  1864. XXchar *s2;
  1865. XX{
  1866. XX    register char *scan1;
  1867. XX    register char *scan2;
  1868. XX    register int count;
  1869.  
  1870. XX    count = 0;
  1871. XX    for (scan1 = s1; *scan1 != '\0'; scan1++) {
  1872. XX        for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  1873. XX            if (*scan1 == *scan2++)
  1874. XX                return(count);
  1875. XX        count++;
  1876. XX    }
  1877. XX    return(count);
  1878. XX}
  1879. XX#endif
  1880. @//E*O*F regexp.c//
  1881. chmod u=rw,g=rw,o=rw $OUT
  1882.  
  1883. echo x - regexp.h
  1884. if test -f regexp.h ; then
  1885.     echo regexp.h exists, putting output in $$regexp.h
  1886.     OUT=$$regexp.h
  1887.     STATUS=1
  1888. else
  1889.     OUT=regexp.h
  1890. fi
  1891. sed 's/^XX//' > $OUT <<'@//E*O*F regexp.h//'
  1892. XX/*
  1893. XX * Definitions etc. for regexp(3) routines.
  1894. XX *
  1895. XX * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
  1896. XX * not the System V one.
  1897. XX */
  1898. XX#define NSUBEXP  10
  1899. XXtypedef struct regexp {
  1900. XX    char *startp[NSUBEXP];
  1901. XX    char *endp[NSUBEXP];
  1902. XX    char regstart;        /* Internal use only. */
  1903. XX    char reganch;        /* Internal use only. */
  1904. XX    char *regmust;        /* Internal use only. */
  1905. XX    int regmlen;        /* Internal use only. */
  1906. XX    char program[1];    /* Unwarranted chumminess with compiler. */
  1907. XX} regexp;
  1908.  
  1909. XXextern regexp *regcomp();
  1910. XXextern int regexec();
  1911. XXextern void regsub();
  1912. XXextern void regerror();
  1913. @//E*O*F regexp.h//
  1914. chmod u=rw,g=rw,o=rw $OUT
  1915.  
  1916. echo x - regmagic.h
  1917. if test -f regmagic.h ; then
  1918.     echo regmagic.h exists, putting output in $$regmagic.h
  1919.     OUT=$$regmagic.h
  1920.     STATUS=1
  1921. else
  1922.     OUT=regmagic.h
  1923. fi
  1924. sed 's/^XX//' > $OUT <<'@//E*O*F regmagic.h//'
  1925. XX/*
  1926. XX * The first byte of the regexp internal "program" is actually this magic
  1927. XX * number; the start node begins in the second byte.
  1928. XX */
  1929. XX#define    MAGIC    0234
  1930. @//E*O*F regmagic.h//
  1931. chmod u=rw,g=rw,o=rw $OUT
  1932.  
  1933. echo x - rv_change.c
  1934. if test -f rv_change.c ; then
  1935.     echo rv_change.c exists, putting output in $$rv_change.c
  1936.     OUT=$$rv_change.c
  1937.     STATUS=1
  1938. else
  1939.     OUT=rv_change.c
  1940. fi
  1941. sed 's/^XX//' > $OUT <<'@//E*O*F rv_change.c//'
  1942. XX#include "rv.h"
  1943.  
  1944. XXvoid
  1945. XXchange()
  1946. XX/*
  1947. XX *  Change - change text
  1948. XX */
  1949. XX{
  1950. XX    register struct li_line      *line;
  1951. XX    register struct sc_screen *sc;
  1952. XX    register struct wi_window *wi;
  1953.  
  1954. XX    sc = &screen;
  1955. XX    wi = &window;
  1956.  
  1957. XX    file.fi_modified = TRUE;
  1958. XX    /*
  1959. XX     * Three cases:  lines, columns, or both
  1960. XX     */
  1961. XX    if (sc->sc_validcol) { /* If columns */
  1962. XX        if (sc->sc_firstline != sc->sc_lastline) { /* If both */
  1963. XX            botprint(TRUE,
  1964. XX                "Cant change columns within multiple lines yet.\n");
  1965. XX            return;
  1966. XX        }
  1967. XX        sc->sc_column = sc->sc_firstcol;
  1968. XX        insert();
  1969. XX    }
  1970. XX    else { /* If lines */
  1971. XX        if (sc->sc_firstline == sc->sc_lastline) {
  1972. XX            /*
  1973. XX             * Simple case - change 1 line
  1974. XX             */
  1975. XX            sc->sc_column = 0;
  1976. XX            sc->sc_firstcol = 0;
  1977. XX            sc->sc_lastcol = sc->sc_curline->li_width-1;
  1978. XX            yank_cmd = ' ';
  1979. XX            if (sc->sc_lastcol >= 0) {
  1980. XX                undo.un_deleted = TRUE;
  1981. XX                yank();  /* Save for later undo */
  1982. XX            }
  1983. XX            sc->sc_curline->li_width = 0;
  1984. XX            sc->sc_curline->li_segments = 1;
  1985. XX            sc->sc_curline->li_text[0] = '\0';
  1986. XX            sc->sc_lastcol = -1;
  1987. XX            insert();
  1988. XX        }
  1989. XX        else {
  1990. XX            /*
  1991. XX             * Change multiple lines
  1992. XX             */
  1993. XX            delete();
  1994. XX            sc->sc_column = 0;
  1995. XX            if (sc->sc_lineno == file.fi_numlines) /* If bottom */
  1996. XX                if (sc->sc_lineno != 1) /* If not top */
  1997. XX                    openline(1);
  1998. XX                else { /* Single line in file, replace */
  1999. XX                    sc->sc_firstcol = 0;
  2000. XX                    sc->sc_lastcol = -1;
  2001. XX                }
  2002. XX            else
  2003. XX                openline(-1);
  2004. XX            botprint(FALSE, "%d lines changed",
  2005. XX                sc->sc_lastline - sc->sc_firstline + 1);
  2006. XX            insert();
  2007. XX        }
  2008. XX    }
  2009. XX}
  2010. @//E*O*F rv_change.c//
  2011. chmod u=rw,g=rw,o=rw $OUT
  2012.  
  2013. echo x - rv_column.c
  2014. if test -f rv_column.c ; then
  2015.     echo rv_column.c exists, putting output in $$rv_column.c
  2016.     OUT=$$rv_column.c
  2017.     STATUS=1
  2018. else
  2019.     OUT=rv_column.c
  2020. fi
  2021. sed 's/^XX//' > $OUT <<'@//E*O*F rv_column.c//'
  2022. XX#include "rv.h"
  2023.  
  2024. XX/*
  2025. XX * Logical to/from physical column conversion functions
  2026. XX */
  2027.  
  2028. XXINT
  2029. XXfile_column(s, maxscreen_col)
  2030. XX/*
  2031. XX * Convert a screen column number to a file column number.
  2032. XX */
  2033. XXregister char    *s;
  2034. XXregister INT maxscreen_col;
  2035. XX{
  2036. XX    register INT    c;
  2037. XX    register INT    file_col, screen_col;
  2038.  
  2039. XX    if (s == NULL) {
  2040. XX        errflag = 1;
  2041. XX        botprint(TRUE, "file_column - text is null.\n");
  2042. XX        return 0;
  2043. XX    }
  2044.  
  2045. XX    file_col = 0;
  2046. XX    screen_col = 0;
  2047. XX    while (c = *s++) {
  2048. XX        if (c < ' ' || c > '~') /* control character */
  2049. XX            if (c == '\t' && !set_list) {
  2050. XX                screen_col += set_tabstops -
  2051. XX                    (screen_col % set_tabstops) - 1;
  2052. XX            } else
  2053. XX                ++screen_col;
  2054. XX        ++file_col;
  2055. XX        ++screen_col;
  2056. XX        if (screen_col > maxscreen_col)
  2057. XX            break;
  2058. XX    }
  2059.  
  2060. XX    return file_col <= 0 ? 0 : file_col-1;
  2061. XX}
  2062.  
  2063.  
  2064.  
  2065. XXINT
  2066. XXscreen_column(s, maxfile_col)
  2067. XX/*
  2068. XX * Convert a file column number to a screen column number.
  2069. XX */
  2070. XXregister char    *s;
  2071. XXregister INT maxfile_col;
  2072. XX{
  2073. XX    register INT    c;
  2074. XX    register INT    file_col, screen_col;
  2075.  
  2076. XX    if (s == NULL) {
  2077. XX        errflag = 1;
  2078. XX        botprint(TRUE, "screen_column - text is null.\n");
  2079. XX        return 0;
  2080. XX    }
  2081.  
  2082. XX    file_col = 0;
  2083. XX    screen_col = 0;
  2084. XX    while (c = *s++) {
  2085. XX        if (c < ' ' || c > '~') /* control character */
  2086. XX            if (c == '\t' && !set_list) {
  2087. XX                if (input_mode && file_col >= maxfile_col) {
  2088. XX                    ++screen_col;
  2089. XX                    break;
  2090. XX                }
  2091. XX                screen_col += set_tabstops - 
  2092. XX                    (screen_col % set_tabstops) - 1;
  2093. XX            } else
  2094. XX                ++screen_col;
  2095. XX        ++file_col;
  2096. XX        ++screen_col;
  2097. XX        if (file_col > maxfile_col)
  2098. XX            break;
  2099. XX    }
  2100.  
  2101. XX    return screen_col <= 0 ? 0 : screen_col-1;
  2102. XX}
  2103. @//E*O*F rv_column.c//
  2104. chmod u=rw,g=rw,o=rw $OUT
  2105.  
  2106. echo x - rv_delcol.c
  2107. if test -f rv_delcol.c ; then
  2108.     echo rv_delcol.c exists, putting output in $$rv_delcol.c
  2109.     OUT=$$rv_delcol.c
  2110.     STATUS=1
  2111. else
  2112.     OUT=rv_delcol.c
  2113. fi
  2114. sed 's/^XX//' > $OUT <<'@//E*O*F rv_delcol.c//'
  2115. XX#include "rv.h"
  2116.  
  2117. XXvoid delete_columns(first, last)
  2118. XX/*
  2119. XX *  Delete - delete columns from current line
  2120. XX */
  2121. XXINT    first,last;
  2122. XX{
  2123. XX    register struct sc_screen *sc;
  2124. XX    register struct li_line   *line;
  2125. XX    register char    *s1, *s2;
  2126.  
  2127. XX    sc = &screen;
  2128. XX    save_Undo();
  2129. XX    line = sc->sc_curline;
  2130. XX    /*
  2131. XX     * Compact line
  2132. XX     */
  2133. XX    s1 = &line->li_text[first];
  2134. XX    s2 = &line->li_text[last+1];
  2135. XX    while (*s1++ = *s2++)
  2136. XX        ;
  2137. XX    /*
  2138. XX     * Draw line
  2139. XX     */
  2140. XX    redraw_curline(line->li_text);
  2141. XX    /*
  2142. XX     * Adjust cursor
  2143. XX     */
  2144. XX    sc->sc_column = first;
  2145. XX    if (sc->sc_column >= line->li_width)
  2146. XX        sc->sc_column = line->li_width-1;
  2147. XX    move_cursor(sc->sc_lineno, sc->sc_column);
  2148. XX}
  2149. @//E*O*F rv_delcol.c//
  2150. chmod u=rw,g=rw,o=rw $OUT
  2151.  
  2152. echo x - rv_dot.c
  2153. if test -f rv_dot.c ; then
  2154.     echo rv_dot.c exists, putting output in $$rv_dot.c
  2155.     OUT=$$rv_dot.c
  2156.     STATUS=1
  2157. else
  2158.     OUT=rv_dot.c
  2159. fi
  2160. sed 's/^XX//' > $OUT <<'@//E*O*F rv_dot.c//'
  2161. XX#include "rv.h"
  2162.  
  2163. XXvoid
  2164. XXrv_dot()
  2165. XX/*
  2166. XX * repeat last change
  2167. XX */
  2168. XX{
  2169. XX    register struct sc_screen *sc;
  2170. XX    register struct ya_yank      *yk;
  2171. XX    INT direction = -1;
  2172. XX    INT saveline, savecol;
  2173.  
  2174. XX    sc = &screen;
  2175. XX    yk = &yank_array[0];
  2176.  
  2177. XX    /*
  2178. XX     * See if there is something to repeat
  2179. XX     */
  2180. XX    if (undo.un_deleted == FALSE && undo.un_inserted == FALSE) {
  2181. XX        flash();
  2182. XX        errflag = 1;
  2183. XX        return;
  2184. XX    }
  2185.  
  2186. XX    /*
  2187. XX     * Put last inserted text
  2188. XX     */
  2189. XX    if (undo.un_inserted) {
  2190. XX        saveline = sc->sc_lineno;
  2191. XX        savecol = sc->sc_column;
  2192. XX        /*
  2193. XX         * Yank text from old location
  2194. XX         */
  2195. XX        move_abs_cursor(undo.un_firstline, 0);
  2196. XX        sc->sc_firstline = undo.un_firstline;
  2197. XX        sc->sc_lastline = undo.un_lastline;
  2198. XX        if (undo.un_validcol == FALSE)
  2199. XX            sc->sc_validcol = FALSE;
  2200. XX        else {
  2201. XX            sc->sc_validcol = TRUE;
  2202. XX            sc->sc_firstcol = undo.un_firstcol;
  2203. XX            sc->sc_lastcol = undo.un_lastcol;
  2204. XX        }
  2205. XX        yank_cmd = '.';
  2206. XX        yank();
  2207. XX        move_abs_cursor(saveline, savecol);
  2208. XX    }
  2209.  
  2210. XX    /*
  2211. XX     * Repeat last deletion
  2212. XX     */
  2213. XX    if (undo.un_deleted && yk->ya_type != YANK_EMPTY) {
  2214. XX        sc->sc_firstline = sc->sc_lineno;
  2215. XX        if (yk->ya_type != YANK_COLS) {
  2216. XX            sc->sc_validcol = FALSE;
  2217. XX            sc->sc_lastline = sc->sc_firstline + yk->ya_numlines-1;
  2218. XX        }
  2219. XX        else {
  2220. XX            sc->sc_validcol = TRUE;
  2221. XX            sc->sc_lastline = sc->sc_firstline;
  2222. XX            sc->sc_firstcol = sc->sc_column;
  2223. XX            sc->sc_lastcol = sc->sc_firstcol + yk->ya_width - 1;
  2224. XX            if (sc->sc_lastcol >= sc->sc_curline->li_width)
  2225. XX                sc->sc_lastcol = sc->sc_curline->li_width-1;
  2226. XX            if (sc->sc_lastcol < 0) {
  2227. XX                flash();
  2228. XX                errflag = 1;
  2229. XX                return;
  2230. XX            }
  2231. XX        }
  2232. XX        yank_cmd = ' ';
  2233. XX        delete();
  2234. XX    }
  2235.  
  2236. XX    /*
  2237. XX     * Repeat last insertion
  2238. XX     */
  2239. XX    if (undo.un_inserted) {
  2240. XX        yank_cmd = '.';
  2241. XX        if (undo.un_validcol == TRUE)
  2242. XX            /*
  2243. XX             * Dot inserts changes before the cursor
  2244. XX             */
  2245. XX            sc->sc_column--;
  2246. XX        put(direction);
  2247. XX    }
  2248. XX}
  2249. @//E*O*F rv_dot.c//
  2250. chmod u=rw,g=rw,o=rw $OUT
  2251.  
  2252. echo Inspecting for damage in transit...
  2253. temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
  2254. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  2255. cat > $temp <<\!!!
  2256.       40     189    1543 BUGFIX
  2257.       26      96     799 BUGFIX2
  2258.       39     128     943 Makefile.bsd
  2259.       38     121     910 Makefile.usg
  2260.       60     314    2087 NEXT_REL
  2261.      103     430    2818 README
  2262.       66     285    1842 binsearch.c
  2263.       20      41     231 copy.c
  2264.       24     168    1052 copyright
  2265.       57      57     593 Manifest
  2266.        8      11      73 regerror.c
  2267.     1237    4440   28158 regexp.c
  2268.       21      86     574 regexp.h
  2269.        5      28     153 regmagic.h
  2270.       68     197    1435 rv_change.c
  2271.       81     235    1483 rv_column.c
  2272.       34      77     604 rv_delcol.c
  2273.       88     217    1726 rv_dot.c
  2274.     2015    7120   47024 total
  2275. !!!
  2276. wc $FILES | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  2277. if test -s $dtemp ; then
  2278.     echo "Ouch [diff of wc output]:"
  2279.     cat $dtemp
  2280.     STATUS=1
  2281. elif test $STATUS = 0 ; then
  2282.     echo "No problems found."
  2283. else
  2284.     echo "WARNING -- PROBLEMS WERE FOUND..."
  2285. fi
  2286. exit $STATUS
  2287.